#ifndef _JOGO_H_
#define _JOGO_H_

#include <conio.h>
#include <math.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>

#include "utypes.h"
#include "bola.h"
#include "bonus.h"
#include "queue.h"
#include "timer.h"
#include "vector2d.h"
#include "aux_menu.h"
#include "kbc.h"
#include "rtc.h"

#ifdef EMBED
	#include "libepc.h"

	#define getKey() ScanCode2Ascii(GetScanCode())
	#define hasKey() ScanCodeRdy()
	#define writeChar(ch) PutChar((ch))
	#define setCursor(row, col) SetCursorPosition((row), (col))
	#define printString(msg) PutString((msg))
	
	#define MAIN void main(long v_mem)

#else
	#include <stdio.h>
	#define getKey() getch()
	#define hasKey() kbhit()
	#define writeChar(ch) printf('%c', (ch))
	#define setCursor(row, col) gotoxy((col), (row))
	#define printString(msg) printf("%s", msg)
	#define MAIN int main(int argc, char** argv)
#endif

/** @defgroup Jogo Jogo
 * @{
 *
 * @brief Funções que executam todo o jogo.
 */

/** Enumeração dos modos de jogo. */
typedef enum{TEMPORIZADO, OBJECTIVOS} ModoJogo;
/** Enumeração das dificuldades. */
typedef enum{FACIL, MEDIO, DIFICIL} Dificuldade;
/** Enumeração de opções que indicam se os bónus estão activados ou não. */
typedef enum{ACTIVADOS, DESACTIVADOS} BonusActivados;

#define CLASS_FILE_NAME "class.txt"

#define VELOCIDADE_JOGADOR_TECLADO 5 // Velocidade da bola do jogador com o teclado
#define NUMERO_INICIAL_BOLAS 4 // Nº inicial de bolas inimigas no modo de jogo temporizado
extern int INTERVALO_ENTRE_NOVAS_BOLAS; // Nº de mili-segundos entre a adição de novas bolas "inimigas"
#define PROB_BONUS_POR_SEGUNDO 12 // Probabilidade (entre 0 e 100) de surgir um bónus em cada segundo
extern int OBJECTIVOS_POR_BOLA; // Nº de objectivos necessários para surgir uma nova bola inimiga


// Scancodes das teclas usadas
#define ESCAPE_KEY 1
#define ENTER_KEY 28
#define UP_KEY 72
#define DOWN_KEY 80
#define LEFT_KEY 75
#define RIGHT_KEY 77
#define UP_RELEASED (72 | 0x80)
#define DOWN_RELEASED (80 | 0x80)
#define LEFT_RELEASED (75 | 0x80)
#define RIGHT_RELEASED (77 | 0x80)

// Constantes usadas no posicionamento dos elementos da barra de estado
#define COL_TITULO 32
#define COL_TEMPO 2
#define COL_OBJECTIVOS 2
#define COL_NBOLAS 68

/** Informações/objectos do jogo. */
typedef struct {
	/** Array de bolas inimigas em jogo. */
	Bola** bolas; 
	/** Nº de bolas inimigas em jogo. */
	int nbolas;
	/** Array de bónus em jogo. */
	Bonus** bonus;
	/** Nº de bónus em jogo. */
	int nbonus;
	/** A bola do jogador. */
	Bola jogador;
	/** Apontador para o míssil em jogo (NULL se inexistente). */
	Bola* missil;
	/** Apontador para o objectivo actual (NULL se for um jogo temporizado. */
	Bola* objectivo;
	/** Nº de objectivos "apanhados". */
	int nobjectivos;
	/** Modo de jogo. */
	ModoJogo modo;
	/** Dificuldade do jogo. */
	Dificuldade dificuldade;
	/** Indica se os bónus estão activados. */
	BonusActivados bonus_activados;
} Jogo;

/** Indica se já se passou tempo suficiente para ser executado um novo "passo" no jogo. */
volatile Bool novo_step;
/** Indica se já se passou mais um segundo. */
volatile Bool segundos_actualizados;

/** Fila para o teclado. */
extern Queue queue_keyboard;
/** Tabela de caracteres. */
extern char* char_table;

/** Função que desenha o menu. */
void drawMenu();
/** Apresenta o menu do jogo. */
void menu();
/** Inicia o jogo e inicializa variáveis e estruturas. */
void start();
/** Função que executa o ciclo principal do jogo. */
void play();
/** Função que move e redesenha todas as bolas e bónus. */
void moveInternalObjects();
/** Verifica se alguma bola inimiga ou míssil colidade com a bola do jogador.
 * @return Se o jogador perdeu.
 */
Bool check_game_over();
/** Verifica de trata de colisões com bónus. */
void checkBonusCollision();
/** Devolve a distância entre dois pontos.
 * @param x1 Coordenada x do 1º ponto.
 * @param y1 Coordenada y do 1º ponto.
 * @param x2 Coordenada x do 2º ponto.
 * @param y2 Coordenada y do 2º ponto.
 * @return Distância entre os dois pontos.
 */
int distance(int x1, int y1, int x2, int y2);
/** Adiciona uma bola ao jogo.
 * @param bola Apontador para a bola a adicionar.
 */
void addBola(Bola* bola);
/** Adiciona um bónus ao jogo.
 * @param bola Apontador para bónus a adicionar.
 */
void addBonus(Bonus* bonus);
/** Remove um bónus do jogo.
 * @param index Índice do bónus a eliminar.
 */
void removeBonus(int index);
/** Elimina todas as informações do jogo da memória. */
void freeJogo();
/** Adiciona uma bola "inimiga" numa posição aleatória e com direcção também aleatória. */
void adicionarBolaInimiga();
/** Adiciona um bónus aleatório numa posição aleatória. */
void adicionarBonus();
/** Avalia e efectua as colisões das bolas. */
void checkBallCollision();
/** Resolve colisões das bolas.
 * @param b1 1º bola.
 * @param b2 2ª bola.
 */
void SolveBallCollision(Bola * b1, Bola * b2);
/** Move o míssil na direcção do jogador (se existir). */
void moverMissil();

/** Função que trata do bónus que pára todas as bolas inimigas. */
void bonus_parar_bolas();
/** Função que trata da bónus (penalização) que pára a bola do jogador. */
void bonus_parar_jogador();
/** Função que trata do bónus que abranda todas as bolas inimigas. */
void bonus_abrandar();
/** Função que trata do bónus (penalização) que acelera todas as bolas inimigas. */
void bonus_acelerar();
/** Função que trata do bónus que torna a bola do jogador invencível. */
void bonus_invencivel();
/** Função que trata do bónus (penalização) que cria um míssil. */
void bonus_missil();

/** Move o objectivo para uma posição aleatória. */
void objectivoMoveRandom();
/** Verificar se o jogador "apanhou" o objectivo, e toma as acções apropriadas. */
void checkObjectivoCollision();

/** Incrementa o nº de segundos jogados em 1, colocando a informação no ecrã (podendo, também, criar um bónus aleatório). */
void updateGameTime();
/** Grava a classificação actual num ficheiro. */
void saveClassificationToFile();

/** @} end of Jogo */

#endif
